package de.negativrekord.blockworld.camera;

import cc.creativecomputing.CCApp;
import cc.creativecomputing.control.CCControl;
import cc.creativecomputing.graphics.CCCamera;
import cc.creativecomputing.graphics.CCGraphics;
import cc.creativecomputing.math.CCMath;
import cc.creativecomputing.math.CCVector3f;

import com.riekoff.particlecubeworld.editor.visual.ABoxVisualFinal;

import de.negativrekord.blockworld.camera.CameraWrapper2.Path;

public class CameraSet {

	float tClose0 = 0f;
	float tClose1 = 0f;
	float tMid = 0f;
	float tFar = 0f;
	
	private class CamControls {
		@CCControl(name = "fov", min = 0, max = 90)
		float _cFov = 20;
		
		@CCControl(name = "offset close", min = -10000, max = 10000)
		float _cOffsetClose = 0;
		
		@CCControl(name = "offset mid", min = -10000, max = 10000)
		float _cOffsetMid = 0;
		
		@CCControl(name = "offset far", min = -10000, max = 10000)
		float _cOffsetFar = 0;
	}
	
	@CCControl(name = "three", column = 2)
	private CamControls _cThreeControls = new CamControls();
	
	@CCControl(name = "two", column = 3)
	private CamControls _cTwoControls = new CamControls();
	
	@CCControl(name = "total", column = 4)
	private CamControls _cTotalControls = new CamControls();
	
	private class EgoCamControls{
		@CCControl(name="move speed", min=0f, max=1f)
		private float _cMoveSpeed = 1f;
		@CCControl(name="look speed", min=0f, max=1f)
		private float _cLookSpeed = 1f;
		
		@CCControl(name="look angle", min=-1f, max=1f)
		private float _cLookAngle = 0f;
		@CCControl(name="offset y", min=-100, max=100)
		private int _cOffsetY = 0;
		@CCControl(name="offset z", min=-100, max=100)
		private int _cOffsetZ = 0;
	}
	
	@CCControl(name = "close ego", column = 5)
	private EgoCamControls _cCloseEgoControls = new EgoCamControls();

	@CCControl(name = "straight ego", column = 6)
	private EgoCamControls _cStraightEgoControls = new EgoCamControls();

	@CCControl(name="speedFar", min=0, max=10f)
	private float _cSpeedFar = 0f;
	
	@CCControl(name="speedMid", min=0, max=10f)
	private float _cSpeedMid = 0f;
	
	@CCControl(name="closeup switch time 0", min=1f, max=10f)
	private float _cSpeedClose0 = 0f;
	
	@CCControl(name="closeup switch time 1", min=1f, max=10f)
	private float _cSpeedClose1 = 0f;
	
	
	
		
	public enum SplitMode {
		TOTAL, 
		TWO, 
		THREE
	};
	
	public enum CameraDistance {
		CLOSE_CLOSE_MID,
		MID_MID_FAR
	};
	
	
	float offsets[][] = {
			{0,1,2},
			{0,2,1},
			{1,0,2},
			{1,2,0},
			{2,0,1},
			{2,1,0},
	};
	
	private float[] randomOffset() {
		return offsets[(int)CCMath.random(0,5.9999f)];
	}
	
	SplitMode _mySplitMode; // = SplitMode.TOTAL;
	CameraDistance _myDistanceMode;
	
	private CameraWrapper2 cam13A;
	private CameraWrapper2 cam13B;
	private CameraWrapper2 cam13C;
	private CameraWrapper2 cam23;
	private CameraWrapper2 cam33;
	
	private ABoxVisualFinal _myVisual;
	private CCGraphics g;
	
	public CameraSet(CCApp theApp, ABoxVisualFinal theVisual) {
		
		_myVisual = theVisual;
		g = theApp.g;
		
		cam13A = new CameraWrapper2(theApp, 1/3f, 0, theVisual.size, theVisual.planes[0]);
		cam13B = new CameraWrapper2(theApp, 1/3f, 0, theVisual.size, theVisual.planes[0]);
		cam13C = new CameraWrapper2(theApp, 1/3f, 0, theVisual.size, theVisual.planes[0]);
		
		cam23 = new CameraWrapper2(theApp,2/3f, 0, theVisual.size, theVisual.planes[0]);
		cam33 = new CameraWrapper2(theApp, 1f, 0,  theVisual.size, theVisual.planes[0]);		
		
		swapMode(0);
		setSplitMode(SplitMode.THREE);
		setCameraDistanceMode(CameraDistance.MID_MID_FAR);
	}
	
	public void recalc (ABoxVisualFinal theVisual) {
		cam13A.setHeightMap(theVisual.planes[0]);
		cam13B.setHeightMap(theVisual.planes[0]);
		cam13C.setHeightMap(theVisual.planes[0]);
		

		cam23.setHeightMap(theVisual.planes[0]);
		cam33.setHeightMap(theVisual.planes[0]);
	}
	
	public void swapMode(int theIndex) {
		if (_mySplitMode == SplitMode.THREE) {
			float[] offset = offsets[theIndex%6]; //randomOffset();
			cam13A.setOffset(offset[0]);
			cam13B.setOffset(offset[1]);
			cam13C.setOffset(offset[2]);
		}
		if (_mySplitMode == SplitMode.TWO) {
			if (theIndex%2==0) {
				cam13A.setOffset(0);
				cam23.setOffset(0.5f);
			}
			else {
				cam13A.setOffset(2);
				cam23.setOffset(0);
			}
		}
	}
	
	public void setSplitMode (SplitMode theMode) {
		_mySplitMode = theMode;
	}
	
	public void setCameraDistanceMode (CameraDistance theDistanceMode) {
		_myDistanceMode = theDistanceMode;
	}
	
	public CCCamera getCurrentCamera() {
		return cam33.camera();
	}
	
	
	public void update(float theDeltaTime) {

		tClose0 = (tClose0 + theDeltaTime / _cSpeedClose0);
		tClose1 = (tClose1 + theDeltaTime / _cSpeedClose1);
		tMid    = (tMid + _cSpeedMid * 0.01f * theDeltaTime)%1f;
		tFar    = (tFar + _cSpeedFar * 0.01f * theDeltaTime)%1f;
		
		switch(_mySplitMode){
		case TOTAL:
			cam33.camera().fov(CCMath.radians(_cTotalControls._cFov));
			switch(_myDistanceMode){
			case MID_MID_FAR:
				cam33.updateMid(tMid, _cTotalControls._cOffsetFar);
				break;
			case CLOSE_CLOSE_MID:
				cam33.updateFar(tFar, _cTotalControls._cOffsetMid);
				break;
			}
			break;
		case TWO:
			cam13A.camera().fov(CCMath.radians(_cThreeControls._cFov));
			cam23.camera().fov(CCMath.radians(_cTwoControls._cFov));
			switch(_myDistanceMode){
			case MID_MID_FAR:
				cam23.updateClose(
					tClose0, 
					_cCloseEgoControls._cMoveSpeed, 
					_cCloseEgoControls._cLookSpeed, 
					new CCVector3f(_cTwoControls._cOffsetMid, _cCloseEgoControls._cOffsetY, _cCloseEgoControls._cOffsetZ), 
					_cCloseEgoControls._cLookAngle
				);
				cam13A.updateFar(tMid, _cThreeControls._cOffsetFar);
				break;
			case CLOSE_CLOSE_MID:
				cam23.updateClose(
					tClose0, 
					_cCloseEgoControls._cMoveSpeed, 
					_cCloseEgoControls._cLookSpeed, 
					new CCVector3f(_cTwoControls._cOffsetClose, _cCloseEgoControls._cOffsetY, _cCloseEgoControls._cOffsetZ), 
					_cCloseEgoControls._cLookAngle
				);
				cam13A.updateStraight(
					tClose0, 
					_cStraightEgoControls._cMoveSpeed, 
					new CCVector3f(_cThreeControls._cOffsetMid, _cStraightEgoControls._cOffsetY, _cStraightEgoControls._cOffsetZ),
					_cStraightEgoControls._cLookAngle
				);
				break;
			}
			break;
		case THREE:
			cam13A.camera().fov(CCMath.radians(_cThreeControls._cFov));
			cam13B.camera().fov(CCMath.radians(_cThreeControls._cFov));
			cam13C.camera().fov(CCMath.radians(_cThreeControls._cFov));
			switch(_myDistanceMode){
			case MID_MID_FAR:
				cam13A.updateMid(tMid, _cThreeControls._cOffsetMid);
				cam13B.updateMid(tMid, _cThreeControls._cOffsetMid);
				cam13C.updateFar(tFar, _cThreeControls._cOffsetFar);
				break;
			case CLOSE_CLOSE_MID:
				cam13A.updateClose(
					tClose0, 
					_cCloseEgoControls._cMoveSpeed, 
					_cCloseEgoControls._cLookSpeed, 
					new CCVector3f(_cThreeControls._cOffsetClose, _cCloseEgoControls._cOffsetY, _cCloseEgoControls._cOffsetZ), 
					_cCloseEgoControls._cLookAngle
				);
				cam13B.updateClose(
					tClose0, 
					_cCloseEgoControls._cMoveSpeed, 
					_cCloseEgoControls._cLookSpeed, 
					new CCVector3f(_cThreeControls._cOffsetClose, _cCloseEgoControls._cOffsetY, _cCloseEgoControls._cOffsetZ), 
					_cCloseEgoControls._cLookAngle
				);
				cam13C.updateStraight(
					tClose0, 
					_cStraightEgoControls._cMoveSpeed, 
					new CCVector3f(_cThreeControls._cOffsetMid, _cStraightEgoControls._cOffsetY, _cStraightEgoControls._cOffsetZ),
					_cStraightEgoControls._cLookAngle
				);
				break;
			}
			break;
		}
	}
	
	public void drawDebug() {
		
		
		switch (_mySplitMode) {
		case TOTAL:
			switch(_myDistanceMode){
			case CLOSE_CLOSE_MID:
				cam33.drawDebug(Path.MID);
				break;
			case MID_MID_FAR:
				cam33.drawDebug(Path.FAR);
				break;
			}
		case TWO:
			switch(_myDistanceMode){
			case CLOSE_CLOSE_MID:
				cam13A.drawDebug(Path.MID);
				cam23.drawDebug(Path.CLOSE);	
				break;
			case MID_MID_FAR:
				cam13A.drawDebug(Path.FAR);
				cam23.drawDebug(Path.MID);	
				break;
			}	
			break;
		case THREE:
			switch(_myDistanceMode){
			case CLOSE_CLOSE_MID:
				cam13A.drawDebug(Path.CLOSE);
				cam13B.drawDebug(Path.CLOSE);
				cam13C.drawDebug(Path.MID);
				break;
			case MID_MID_FAR:
				cam13A.drawDebug(Path.MID);
				cam13B.drawDebug(Path.MID);
				cam13C.drawDebug(Path.FAR);
				break;
			}	
			break;
		default: break;
		}
		
	}
	
	public void draw() {
		switch (_mySplitMode) {
		case TOTAL:
			cam33.draw();
			_myVisual.render(g);
			break;
		case TWO:
			cam13A.draw();			
			_myVisual.render(g);
			cam23.draw();			
			_myVisual.render(g);
			break;
		case THREE:
			cam13A.draw();
			_myVisual.render(g);
			cam13B.draw();
			_myVisual.render(g);
			cam13C.draw();
			_myVisual.render(g);
			break;
		default: break;
		}
	}
}
